﻿// Machine Learning Library
// ocr  Framework
// Copyright © Dong Nguyen, 2010-2011
// crackit.vn at gmail.com
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Ink;
using System.IO;
using System.Windows.Media.Imaging;
using System.Windows.Media;
namespace utility
{
    // base64 - > strokes collection -> bitmap -> resize -> grayscale -> thresold -> matrix -> feature vector 
    
    public  class tools
    {
        /// <summary>
        /// base64 code to strokes collection
        /// </summary>
        /// <param name="sBase64">base64 code is type of string</param>
        /// <returns>stroke collection belong to system.windows.ink package</returns>
        public static StrokeCollection Base64ToStrokes(string sBase64)
        {
            try
            {
                StrokeCollection sc = null;
                // Base64 to double-array.
                byte[] isfdoubles = Convert.FromBase64String(sBase64);
                // Save to a stream.
                using (MemoryStream ms = new MemoryStream())
                {
                    ms.Write(isfdoubles, 0, isfdoubles.Length);
                    ms.Position = 0;     // Wind back.
                    // Get StrokeCollection from stream.
                    sc = new StrokeCollection(ms);
                }
                return sc;
            }
            catch
            {
                return null;
            }
        }
        /// <summary>
        /// convert strokes collection  to bitmap
        /// </summary>
        /// <param name="inkStrokes">strokes collection</param>
        /// <returns>return bitmap </returns>
        public static System.Drawing.Bitmap StrokesToGDIBitmap(StrokeCollection inkStrokes)
        {
            try
            {
                // 1) Use bounding rectangle from strokes as outer size of image.
                Rect recBounds = inkStrokes.GetBounds();

                /*
                // 2) Or use size of canvas.
                Rect recBounds = new Rect();
                recBounds.X = 0;
                recBounds.Y = 0;
                recBounds.Width = m_inkCanvas.Width;
                recBounds.Height = m_inkCanvas.Height;
                */

                DrawingVisual dVisual = new DrawingVisual();
                DrawingContext dContext = dVisual.RenderOpen();
                dContext.PushTransform(new TranslateTransform(-recBounds.X, -recBounds.Y));

                // Has normally a transparent background.
                dContext.DrawRectangle(Brushes.White, null, recBounds);
                inkStrokes.Draw(dContext);
                dContext.Close();

                RenderTargetBitmap oBitmap =
                    new RenderTargetBitmap((int)recBounds.Width,
                    (int)recBounds.Height,
                    96, 96, PixelFormats.Pbgra32);

                oBitmap.Render(dVisual);
                BitmapEncoder oEncoder = null;

                oEncoder = new BmpBitmapEncoder();
                if (oEncoder != null)
                {
                    oEncoder.Frames.Add(BitmapFrame.Create(oBitmap));

                    byte[] temp;
                    using (MemoryStream mm = new MemoryStream())
                    {
                        oEncoder.Save(mm);
                        temp = mm.ToArray();
                    }

                    MemoryStream mk = new MemoryStream(temp);

                    return new System.Drawing.Bitmap(mk);
                }
                else return null;
            }
            catch
            {
                return null;
            }
        }
        /// <summary>
        /// convert a strokes collection to directx image
        /// </summary>
        /// <param name="inkStrokes">strokes collection</param>
        /// <returns>image</returns>
        public static RenderTargetBitmap StrokesToDXBitmap(StrokeCollection inkStrokes)
        {
            try
            {
                // 1) Use bounding rectangle from strokes as outer size of image.
                Rect recBounds = inkStrokes.GetBounds();

                /*
                // 2) Or use size of canvas.
                Rect recBounds = new Rect();
                recBounds.X = 0;
                recBounds.Y = 0;
                recBounds.Width = m_inkCanvas.Width;
                recBounds.Height = m_inkCanvas.Height;
                */

                DrawingVisual dVisual = new DrawingVisual();
                DrawingContext dContext = dVisual.RenderOpen();
                dContext.PushTransform(new TranslateTransform(-recBounds.X, -recBounds.Y));

                // Has normally a transparent background.
                dContext.DrawRectangle(Brushes.Transparent, null, recBounds);
                inkStrokes.Draw(dContext);
                dContext.Close();

                RenderTargetBitmap oBitmap =
                    new RenderTargetBitmap((int)recBounds.Width,
                    (int)recBounds.Height,
                    96, 96, PixelFormats.Pbgra32);

                oBitmap.Render(dVisual);
                return oBitmap;
            }
            catch
            {
                return null;
            }
        }
        /// <summary>
        /// decode base64 to bitmap
        /// </summary>
        /// <param name="sbase64">sbase64 :type of string</param>
        /// <returns>system.drawing.bitmap</returns>
        public static System.Drawing.Bitmap Base64ToGDIBitmap(string sbase64)
        {
           return StrokesToGDIBitmap(Base64ToStrokes(sbase64));
        }
        /// <summary>
       /// convert a GDI bitmap to double matrix 
       /// </summary>
       /// <param name="bm">bitmap to resize</param>
       /// <returns>double[,] matrix</returns>
        public static double[,] GDIBitmapToMatrix(System.Drawing.Bitmap bm)
        {
            int row = 20;
            int col = 20;
            double[,] r = new double[20 , 20];

            for (int i = 0; i < row; i++)
                for (int j = 0; j < col; j++)
                    r[i, j] = 0d;
            for (int i = 0; i < bm.Height ; i++)
                for (int j = 0; j < bm.Width ; j++)
                {
                    
                        if (bm.GetPixel(j , i).R == 255)
                            r[i, j] = 0d;
                        else
                            r[i, j] = 1d;
                  
                    //convert(x, y, true);
                  
                }
                    return r;
        }
        public static double[,] GDIBitmapToMatrix(System.Drawing.Image bm)
        {
            int row = 20;
            int col = 20;
            
            System.Drawing.Bitmap bm2 = (System.Drawing.Bitmap)bm;
            double[,] r = new double[20, 20];

            for (int i = 0; i < row; i++)
                for (int j = 0; j < col; j++)
                    r[i, j] = 0d;
            for (int i = 0; i < bm.Height; i++)
                for (int j = 0; j < bm.Width; j++)
                {

                    if ((bm2.GetPixel(j, i).R == 255))
                        r[i, j] = 0d;
                    else
                        r[i, j] = 1d;

                    //convert(x, y, true);

                }
            return r;
        }
        /// <summary>
        /// convert a gdi bitmap to vector
        /// </summary>
        /// <param name="bm">bitmap to resize</param>
        /// <return>vector</returns>
        public static double[] GDIBitmapToVector(System.Drawing.Bitmap bm)
        {

            double[,] r = GDIBitmapToMatrix(bm);
            int row = bm.Height;
            int col = bm.Width;
            
            double[] d = new double[r.Length];

            for (int i = 0; i < row; i++)
                for (int j = 0; j < col; j++)
                    d[i * col + j] = r[i, j];
            return d;
        }
        public static System.Drawing.Bitmap MatrixToEquavalentImage(double[,] d)
        {
            System.Drawing.Bitmap bm = new System.Drawing.Bitmap (20,20);
            for(int i = 0 ; i < 20 ; i++)
                for (int j = 0; j < 20; j++)
                {
                    if (d[j, i] == 1d)
                        bm.SetPixel(i, j, System.Drawing.Color.Black);
                    else bm.SetPixel(i, j, System.Drawing.Color.White); 

                }
            return bm;

       }
        public static System.Drawing.Bitmap inVerses(System.Drawing.Bitmap bm)
        {
            for (int i = 0; i < bm.Height; i++)
                for (int j = 0; j < bm.Width; j++)
                {
                    if (bm.GetPixel(j, i).R == 255)
                        bm.SetPixel(j, i, System.Drawing.Color.Black);
                    else
                        bm.SetPixel(j, i, System.Drawing.Color.White);
                }
            return bm;
        }
        public static T convert<T>( T x , T y , bool check)
        {
            if (check)
                return x;
            else return y;
        }
        public static string StrokesToBase64(StrokeCollection inkStrokes)
        {
            
            try
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    // Save strokes from InkCanvas to a stream as ISF.
                    inkStrokes.Save(ms);
                    // Convert doubles from stream to Base64 text.
                    byte[] isfdoubles = ms.ToArray();
                    return Convert.ToBase64String(isfdoubles,
                           Base64FormattingOptions.InsertLineBreaks);
                }
            }
            catch
            {
                return "";
            }
        }
        
    }
}
